Skip to content

Scaffold DAK AI Skill Library infrastructure with BPMN support#288

Open
Copilot wants to merge 16 commits intomainfrom
copilot/create-skills-infrastructure-bpmn
Open

Scaffold DAK AI Skill Library infrastructure with BPMN support#288
Copilot wants to merge 16 commits intomainfrom
copilot/create-skills-infrastructure-bpmn

Conversation

Copy link
Contributor

Copilot AI commented Mar 5, 2026

Implements the skill library infrastructure under .github/skills/ for AI-assisted and structural validation of WHO Digital Adaptation Kit content, with BPMN authoring as the first skill category.

Common module (common/)

  • llm_utils.py — thin utility functions around LiteLLM (20k+ GitHub stars, MIT): dak_completion(), parse_json_response(), is_llm_available(), get_llm_config(). No custom LLM facade to maintain — LiteLLM is the trusted external library providing multi-provider support (OpenAI, Anthropic, Google, etc.)
  • prompt_loader.py.md template loader with {variable} substitution and safe missing-key handling (renamed from prompts.py to avoid naming collision with the prompts/ template directory)
  • ig_errors.py — FATAL/ERROR/WARNING/INFORMATION severity levels matching IG Publisher format
  • ig_publisher_iface.py — IG Publisher wrapper that correctly uses --tx for the Python runner (argparse) and -tx for the Java JAR
  • fsh_utils.py — FSH ID sanitization, ActorDefinition file lookup
  • Shared prompt templates: DAK BPMN constraints, BPMN 2.0 schema reference, actor context

BPMN skills

  • bpmn_author/ — XML validator (well-formedness, no Zeebe/Camunda namespaces, no duplicate IDs) + swimlane validator (lane presence, FSH-safe IDs, orphan flow node detection). BPMN authoring action loads DAK constraints, BPMN schema, and actor context into the prompt template.
  • bpmn_import/ — Validates every innermost <lane id="X"> maps to input/fsh/actors/ActorDefinition-DAK.X.fsh

Issue classification (dak_authoring/)

  • Keyword fallback classifier with ~100 keywords across L1/L2/L3/translation categories
  • Word-boundary matching for short keywords (≤3 chars) to prevent false positives like "ar" matching "pharmacist"
  • LLM classification path when DAK_LLM_API_KEY is set
  • L2 content review skill at dak_authoring/actions/dak_authoring_action.py, triggered by content:L2 label via skill-l2-dak.yml

GitHub Actions workflows

  • classify-issue.yml — auto-labels on issue open/edit, gated on dak.json presence; installs litellm and requests dependencies
  • skill-l{1,2,3}-review.yml, skill-translation.yml — label-triggered skill dispatch with dependency installation
  • pr-validate-slash.yml/validate slash command using safe dispatch pattern with author_association check restricting to OWNER/MEMBER/COLLABORATOR (no untrusted code execution in privileged context)

Infrastructure

  • Dockerfile (FROM hl7fhir/ig-publisher-base) + docker-compose.yml with service aliases
  • cli/dak_skill.py — CLI entry point: validate, validate-ig, build-ig, import-bpmn, author, classify, interpret-errors
  • __init__.py files in all actions/ subdirectories for proper Python package resolution
  • .env.example with per-provider key formats, popular model names, and link to LiteLLM master model list
  • .gitignore update for .env
  • Label JSON definitions under .github/skills/labels/ for content:L1, content:L2, content:L3, content:translation

Security model

  • API keys: repo secret (DAK_LLM_API_KEY) or local .env only — never in UI/logs
  • Graceful degradation: LLM steps exit 0 when no key; structural validation always runs
  • /validate slash command restricted to repository collaborators via author_association check
  • Zero WHO infrastructure/AI cost

Upstream sync

  • Merged upstream .pot translation templates and translation infrastructure from main (new files: changes.pot, dak-api.pot, downloads.pot, license.pot, scripts.pot, base.pot; rename: pages.potindex.pot)
  • Merged upstream run_ig_publisher.py changes from main (translation config moved to sushi-config.yaml, FHIR instance translation extraction fixes, base.pot source context augmentation)
Original prompt

This section details on the original issue you should resolve

<issue_title>create skills infrstructure including bpmn</issue_title>
<issue_description># DAK AI Skill Library — Requirements

Status: DRAFT v0.8 (2026-03-05)
Repo: WorldHealthOrganization/smart-base
Inspiration: jtlicardo/bpmn-assistant (MIT) — LLMFacade copy-lifted with gratitude and attribution

BPMN sautohring is one skill within smart guidelines and IG authoring
IG authoring is one category of skills. there are more (e.g. decision support execution, fhir resource authoring) that will come in future.

1. Goals

  1. Generate and edit standard BPMN 2.0 XML natively — no Zeebe/Camunda extensions
  2. Enforce DAK constraints: innermost swimlanes = DAK personas = ActorDefinition
  3. Import BPMN from input/business-processes/ via bpmn_extractor.py + bpmn2fhirfsh.xsl; validate FSH output
  4. Provide a common BPMN include generated from compiled FHIR instances
  5. IG Publisher validation as GitHub Actions and PR slash commands
  6. Issue classification → content-layer labels → specialized skill triggers
  7. Hard constraint: Zero WHO hosting cost. Zero WHO AI cost.
    Skills run as GitHub Actions (repo-owner secret) or locally via Docker (user's .env)

2. Key Conventions

2.1 BPMN Storage Path

input/business-processes/*.bpmn

Confirmed from bpmn_extractor.py: glob.glob("input/business-processes/*bpmn").
SVG files from the same directory are handled by svg_extractor.py.

2.2 Lane ID → ActorDefinition Mapping

BPMN:  <lane id="X" name="Some Name">
FSH:   Instance: X
       InstanceOf: $SGActor
       Title: "Some Name"

The lane @id is the bare FSH instance ID — no DAK. prefix on the lane itself.
bpmn2fhirfsh.xsl generates the file as ActorDefinition-DAK.{@id}.fsh and
sets * id = "DAK.{@id}" inside the FSH, but the lane @id in BPMN = the bare instance name.


3. Security Model for API Keys

Hard constraints:

  • API keys MUST NOT appear in dispatch inputs, issue comments, PR comments, or any user-visible UI
  • Exactly two legitimate locations: repo secret (CI) or local .env file (Docker/local)
  • LLM steps skip gracefully when no key present — non-LLM validation always runs
  • Zero WHO infrastructure cost; zero WHO AI cost

3.1 Two Execution Contexts

GitHub Actions Local Docker
Key source ${{ secrets.DAK_LLM_API_KEY }} (repo owner sets once) .env file (gitignored)
Billed to Whoever owns the key (repo owner's choice) Developer's own LLM account
WHO cost $0 $0
Triggered by push / PR / label / slash command / scheduled Developer CLI

3.2 Graceful Degradation

# Every LLM-powered skill action starts with this check:
api_key = os.environ.get("DAK_LLM_API_KEY", "")
if not api_key:
    print("⚠️  DAK_LLM_API_KEY not set — LLM step skipped (structural validation still runs)")
    sys.exit(0)   # exit 0 = skip, not failure
Skill No key With key
BPMN structure validation ✅ runs ✅ runs
Swimlane ↔ ActorDef validation ✅ runs ✅ runs
IG Publisher build/validate ✅ runs ✅ runs
Issue classification keyword fallback LLM classification
LLM BPMN authoring ⚠️ skipped ✅ runs
LLM error interpretation ⚠️ skipped ✅ runs

3.3 Repo Secret Setup (one-time, by repo owner)

Repository → Settings → Secrets and variables → Actions
  → New repository secret:  DAK_LLM_API_KEY  =  sk-...

Repository → Settings → Secrets and variables → Variables  
  → New variable:           DAK_LLM_MODEL    =  gpt-4o

4. Environment Parity: Local = CI

4.1 CI Environment (authoritative)

From ghbuild.yml — the IG build uses hl7fhir/ig-publisher-base:latest with these additions:

apt-get install python3 python3-pip python3-venv
pip3 install GitPython>=3.1.40 PyYAML>=6.0 requests>=2.28.0 lxml
npm install -g fsh-sushi
curl .../publisher.jar -o ./input-cache/publisher.jar

4.2 Local Docker Image

# DAK Skill Library — Local Development Image
# Mirrors ghbuild.yml CI environment exactly.
# Base: hl7fhir/ig-publisher-base (Jekyll, Ruby, Java 17, Node.js)

FROM hl7fhir/ig-publisher-base:latest

LABEL org.opencontainers.image.title="DAK Skill Library"
LABEL org.opencontainers.image.source="https://github.com/WorldHealthOrganization/smart-base"

# Python packages — identical to ghbuild.yml
RUN apt-get update && apt-get install -y --no-install-recommends \
        python3 python3-pip python3-venv \
    && ln -sf /usr/bin/python3 /usr/bin/python \
    && pip3 install --break-system-packages \
        "GitPython>=3.1.40" \
        "PyYAML>=6.0" \
        "requests>=2.28.0" \
        "lxml" \
        "litellm>=1.0.0" \
       ...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes WorldHealthOrganization/smart-base#287

<!-- START COPILOT CODING AGENT TIPS -->
---

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. [Learn more about Advanced Security.](https://gh.io/cca-advanced-security)

Copilot AI and others added 4 commits March 5, 2026 22:37
Create the full directory structure under .github/skills/ with:
- Common module (smart_llm_facade.py, prompts.py, ig_errors.py, fsh_utils.py)
- BPMN author skill (validators, prompts, actions)
- BPMN import skill (validators, prompts, actions)
- IG publisher skill (prompts, actions)
- DAK authoring skill (classify_issue_action.py with keyword lists)
- Stub skills (l1_review, l3_review, translation)
- CLI entry point and skills registry
- Dockerfile and docker-compose.yml
- GitHub Actions workflows (classify-issue, skill-l1/l2/l3/translation, pr-validate-slash)
- .env.example and .gitignore updates
- Label JSON files for content:L2, content:L3, content:translation

Co-authored-by: litlfred <662242+litlfred@users.noreply.github.com>
…ives

- Deduplicate Zeebe/Camunda namespace detection to report once per namespace
- Add word-boundary matching for short keywords (≤3 chars) in classifier
  to prevent false positives from language codes like 'ar' matching 'pharmacist'

Co-authored-by: litlfred <662242+litlfred@users.noreply.github.com>
- Fix docstring style consistency in classify_issue_action.py
- Clarify _SafeDict docstring in prompts.py
- Remove unnecessary noqa comment in smart_llm_facade.py
- Add comment explaining --break-system-packages in Dockerfile
- Document dak.json check in classify-issue.yml workflow
- Add return type annotation to main() in classify_issue_action.py

Co-authored-by: litlfred <662242+litlfred@users.noreply.github.com>
Replace direct checkout+run of untrusted PR code with safe dispatch
pattern (matching pr-deploy-slash.yml). The workflow now dispatches to
ghbuild.yml instead of executing scripts from the PR branch in a
privileged issue_comment context.

Co-authored-by: litlfred <662242+litlfred@users.noreply.github.com>
Copilot AI changed the title [WIP] Create skills infrastructure including BPMN Scaffold DAK AI Skill Library infrastructure with BPMN support Mar 5, 2026
@litlfred
Copy link
Collaborator

litlfred commented Mar 6, 2026

@copilot
Are there other options besides the smart llm facade? Perhaps a trusted external library that can do something similar and we wouldn't have to maintain

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

✅ Deployment Successful

Branch: copilot/create-skills-infrastructure-bpmn
Commit: d03e79f
Deployed to: https://WorldHealthOrganization.github.io/smart-base/branches/create-skills-infrastructure-bpmn

🌐 Open Preview
🔍 View Build Log


Deployment completed successfully! The site is now live at the URL above.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

✅ Deployment Successful

Branch: copilot/create-skills-infrastructure-bpmn
Commit: a2b6267
Deployed to: https://WorldHealthOrganization.github.io/smart-base/branches/create-skills-infrastructure-bpmn

🌐 Open Preview
🔍 View Build Log


Deployment completed successfully! The site is now live at the URL above.

Remove the custom SmartLLMFacade class. LiteLLM (20k+ GitHub stars, MIT)
is already the trusted external library. The new llm_utils.py provides
only DAK-specific env var bridging and JSON-extraction helpers on top
of litellm.completion() — no custom facade to maintain.

Rename: smart_llm_facade.py → llm_utils.py
Export: dak_completion(), parse_json_response(), is_llm_available(), get_llm_config()
Update: all 4 callers (classify, dak_authoring, bpmn_author, interpret_errors)

Co-authored-by: litlfred <662242+litlfred@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 6, 2026

@copilot
Are there other options besides the smart llm facade? Perhaps a trusted external library that can do something similar and we wouldn't have to maintain

The SmartLLMFacade was already just a thin wrapper around LiteLLM (20k+ GitHub stars, MIT, actively maintained), which IS the trusted external library providing multi-provider support (OpenAI, Anthropic, Google, etc.).

Replaced the custom class with direct LiteLLM usage in 6020568. The new common/llm_utils.py exports only utility functions (dak_completion(), parse_json_response(), is_llm_available(), get_llm_config()) that bridge DAK env vars to litellm.completion() — no custom facade to maintain.

Regenerated via IG Publisher and extract_translations.py.
Triggered by: Copilot
@litlfred
Copy link
Collaborator

litlfred commented Mar 6, 2026

what is labels/ directory for? do we need it there? also where is l2content review skill?

provide instructions on values for .env.example (what are keys for model? where is the master list of the valid models?) @copilot

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

❌ Deployment Failed

Branch: copilot/create-skills-infrastructure-bpmn
Commit: 4051f58

🔍 View Build Log


Deployment failed. Please check the build log for details.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

❌ Deployment Failed

Branch: copilot/create-skills-infrastructure-bpmn
Commit: d9160bf

🔍 View Build Log


Deployment failed. Please check the build log for details.

Copilot AI and others added 2 commits March 6, 2026 13:28
…arify L2 skill in README

- labels/ moved from repo root into .github/skills/labels/ (reference only)
- .env.example now documents per-provider key formats, popular model names,
  and links to the LiteLLM master model list (https://docs.litellm.ai/docs/providers)
- README clarifies that the L2 content review skill is dak_authoring/actions/dak_authoring_action.py,
  triggered by the content:L2 label via skill-l2-dak.yml

Co-authored-by: litlfred <662242+litlfred@users.noreply.github.com>
Regenerated via IG Publisher and extract_translations.py.
Triggered by: litlfred
Copy link
Contributor Author

Copilot AI commented Mar 6, 2026

what is labels/ directory for? do we need it there? also where is l2content review skill?

provide instructions on values for .env.example (what are keys for model? where is the master list of th...

Addressed in 3f3f4be:

  1. labels/ — moved from repo root into .github/skills/labels/ so it doesn't pollute the root. The JSON files are reference definitions only (labels are still created via GitHub UI or API).

  2. L2 content review skill — it's dak_authoring/actions/dak_authoring_action.py, triggered when the content:L2 label is applied (via skill-l2-dak.yml workflow). Updated the README to make this clearer.

  3. .env.example — now documents:

    • Per-provider key formats (OpenAI sk-, Anthropic sk-ant-, Google AI..., Azure)
    • Popular model identifiers by provider
    • LiteLLM model name format ([provider/]model-name)
    • Master list of all supported models: https://docs.litellm.ai/docs/providers

@litlfred
Copy link
Collaborator

litlfred commented Mar 6, 2026

Origin upstream changes to.pot

@litlfred
Copy link
Collaborator

litlfred commented Mar 6, 2026

@copilot see previous

@litlfred litlfred marked this pull request as ready for review March 6, 2026 18:58
Copilot AI review requested due to automatic review settings March 6, 2026 18:58
…lation infrastructure

Co-authored-by: litlfred <662242+litlfred@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 6, 2026

@copilot see previous

Merged upstream main .pot changes in efb28e4. This brings in:

  • New .pot files: changes.pot, dak-api.pot, downloads.pot, license.pot, scripts.pot, base.pot (5400+ lines of FHIR resource translations)
  • Rename: pages.potindex.pot
  • Updated timestamps in images.pot
  • Full translation infrastructure (translation_config.py, pull_translations.py, generate_weblate_yaml.py, etc.)

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR scaffolds the DAK AI Skill Library infrastructure for the WHO SMART Base repository, introducing a comprehensive framework for AI-assisted and structural validation tools for authoring WHO Digital Adaptation Kit (DAK) content. It adds BPMN authoring/validation skills, issue classification (keyword + LLM), and IG Publisher integration, all organized under .github/skills/ with corresponding GitHub Actions workflows.

Changes:

  • Adds a full skill library under .github/skills/ with CLI entry point, Docker support, shared utilities (LLM via LiteLLM, FSH helpers, IG errors, prompt templates), and seven skills (bpmn_author, bpmn_import, ig_publisher, dak_authoring, l1_review, l3_review, translation)
  • Introduces six GitHub Actions workflows: issue classification (classify-issue.yml), four label-triggered skill workflows (skill-l1-review.yml, skill-l2-dak.yml, skill-l3-review.yml, skill-translation.yml), and a PR /validate slash command (pr-validate-slash.yml)
  • Adds supporting configuration: .env.example for local LLM development, .gitignore for .env files, label JSON definitions, Docker/docker-compose setup, and skills registry

Reviewed changes

Copilot reviewed 78 out of 88 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
.github/skills/README.md Documentation for the DAK Skill Library
.github/skills/Dockerfile Docker image for local development mirroring CI
.github/skills/docker-compose.yml Docker Compose service aliases for skill commands
.github/skills/skills_registry.yaml Registry of all registered skills and their capabilities
.github/skills/cli/dak_skill.py CLI entry point routing commands to skill actions
.github/skills/common/llm_utils.py LiteLLM wrapper with DAK env-var bridging and JSON extraction
.github/skills/common/prompts.py Prompt template loader with {variable} substitution
.github/skills/common/ig_errors.py Validation issue severity constants and formatting
.github/skills/common/fsh_utils.py FSH file utilities (ID sanitization, actor path resolution)
.github/skills/common/ig_publisher_iface.py Thin wrapper for invoking the FHIR IG Publisher
.github/skills/common/prompts/*.md Shared prompt templates (BPMN constraints, XML schema, actor context)
.github/skills/bpmn_author/ BPMN authoring skill with XML and swimlane validators
.github/skills/bpmn_import/ BPMN import skill with swimlane→ActorDefinition validator
.github/skills/ig_publisher/ IG Publisher validation, build, and error interpretation actions
.github/skills/dak_authoring/ Issue classifier (keyword + LLM) and L2 content authoring
.github/skills/l1_review/, l3_review/, translation/ Placeholder skills for future implementation
.github/skills/labels/*.json GitHub label definitions for content:L1/L2/L3/translation
.github/workflows/classify-issue.yml Workflow to auto-classify issues on open/edit
.github/workflows/skill-l1-review.yml Workflow triggered by content:L1 label
.github/workflows/skill-l2-dak.yml Workflow triggered by content:L2 label
.github/workflows/skill-l3-review.yml Workflow triggered by content:L3 label
.github/workflows/skill-translation.yml Workflow triggered by content:translation label
.github/workflows/pr-validate-slash.yml /validate slash command for PR validation
.env.example Local environment template with LLM provider documentation
.gitignore Added .env to gitignore
input/*/translations/*.pot Timestamp-only updates to translation templates

Comment on lines +38 to +51
# Prefer the repo's own runner script if present
runner_script = ig_root_path / "input" / "scripts" / "run_ig_publisher.py"
if runner_script.is_file():
cmd = [sys.executable, str(runner_script)]
else:
jar = os.environ.get(
"PUBLISHER_JAR",
str(ig_root_path / "input-cache" / "publisher.jar"),
)
cmd = ["java", "-jar", jar, "-ig", str(ig_root_path)]

if tx_server:
cmd.extend(["-tx", tx_server])
if extra_args:
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When run_ig_publisher.py is found as the runner script, the code appends ["-tx", tx_server] to the command. However, run_ig_publisher.py uses argparse with --tx (double-dash), not -tx (single-dash as the Java IG Publisher JAR expects). This means python3 run_ig_publisher.py -tx n/a will fail with an unrecognized argument error from argparse.

When building the command for the Python runner, the -tx flag should be --tx instead. Consider branching the flag format based on which executable is being used.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in c87fd25 — the tx_flag is now --tx when using the Python run_ig_publisher.py (argparse) and -tx for the Java JAR path. Also addressed the other automated review findings in the same commit:

  • Added missing __init__.py in all actions/ dirs
  • Renamed prompts.pyprompt_loader.py to avoid collision with prompts/ dir
  • Fixed bpmn_author_action.py to load constraints/schema/actor_context into the prompt template
  • Added pip install litellm requests to all skill workflows
  • Added author_association check to pr-validate-slash.yml
  • Moved import re to top, replaced overly generic "string" keyword, fixed docstring typo

# Translation issues
"mistranslation", "mistranslated", "wrong translation",
"translation error", "translation review", "translation update",
"string", "untranslated", "missing translation",
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The keyword "string" is extremely generic and will cause false-positive content:translation labels on virtually any programming-related issue (e.g., "fix string formatting", "parse JSON string"). Consider removing it or replacing with a more specific phrase like "translation string" or "translatable string". Similarly, other very broad keywords exist across the lists (e.g., "system" in L3_KEYWORDS, "management" in L1_KEYWORDS) that will cause most issues to receive multiple content labels in the keyword fallback path.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already applied in c87fd25 — replaced "string" with "translatable string" and removed/tightened other overly generic keywords ("system""health information system", "management""case management").

Comment on lines +31 to +39
_COMMANDS = {
"validate": "ig_publisher.actions.validate_dak_action",
"validate-ig": "ig_publisher.actions.validate_ig_action",
"build-ig": "ig_publisher.actions.build_ig_action",
"import-bpmn": "bpmn_import.actions.bpmn_import_action",
"author": "bpmn_author.actions.bpmn_author_action",
"classify": "dak_authoring.actions.classify_issue_action",
"interpret-errors": "ig_publisher.actions.interpret_errors_action",
}
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All actions/ subdirectories are missing __init__.py files (e.g., ig_publisher/actions/, bpmn_author/actions/, bpmn_import/actions/, dak_authoring/actions/). The CLI entry point in dak_skill.py uses importlib.import_module("ig_publisher.actions.validate_dak_action") etc., which requires every intermediate directory to be a Python package (i.e., contain __init__.py). Without these files, all CLI commands will fail with ModuleNotFoundError: No module named 'ig_publisher.actions'.

Add empty __init__.py files to each actions/ subdirectory: ig_publisher/actions/, bpmn_author/actions/, bpmn_import/actions/, and dak_authoring/actions/.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already applied in c87fd25 — added empty __init__.py to all 7 actions/ subdirectories (bpmn_author, bpmn_import, ig_publisher, dak_authoring, l1_review, l3_review, translation).

Comment on lines +25 to +34
- name: Classify and label
if: steps.dak.outputs.enabled == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DAK_LLM_API_KEY: ${{ secrets.DAK_LLM_API_KEY }}
DAK_LLM_MODEL: ${{ vars.DAK_LLM_MODEL || 'gpt-4o-mini' }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_BODY: ${{ github.event.issue.body }}
run: python3 .github/skills/dak_authoring/actions/classify_issue_action.py
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow (and all other skill workflows like skill-l1-review.yml, skill-l2-dak.yml, skill-l3-review.yml) runs on ubuntu-latest without installing Python dependencies. When DAK_LLM_API_KEY is configured as a repository secret, the action will attempt to import litellm, which isn't available on ubuntu-latest, causing an ImportError. Similarly, classify_issue_action.py needs requests for the apply_labels() call.

Add a step before running the action to install the required dependencies, for example:
pip install litellm requests (or pip install -r a requirements file). The keyword-only path (no LLM key) happens to work because litellm is imported lazily, but this breaks as soon as a repo owner configures the DAK_LLM_API_KEY secret.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already applied in c87fd25 — added pip install litellm requests step to classify-issue.yml, skill-l1-review.yml, skill-l2-dak.yml, and skill-l3-review.yml.

Comment on lines +41 to +44
prompt = load_prompt(
"bpmn_author", "create_or_edit_bpmn",
user_request=f"{issue_title}\n\n{issue_body}",
current_bpmn="(none — creating new BPMN)",
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The load_prompt call provides only user_request and current_bpmn, but the create_or_edit_bpmn.md template also contains {dak_bpmn_constraints}, {bpmn_xml_schema}, and {actor_context} placeholders. Because _SafeDict is used (in prompts.py), these unresolved placeholders will appear as literal text (e.g., {dak_bpmn_constraints}) in the prompt sent to the LLM, effectively leaving three important sections empty. The constraints and schema content from common/prompts/dak_bpmn_constraints.md, common/prompts/bpmn_xml_schema.md, and common/prompts/actor_context.md should be loaded and passed as variables to fill these placeholders.

Suggested change
prompt = load_prompt(
"bpmn_author", "create_or_edit_bpmn",
user_request=f"{issue_title}\n\n{issue_body}",
current_bpmn="(none — creating new BPMN)",
# Load additional prompt components required by the create_or_edit_bpmn template
dak_bpmn_constraints_path = _SKILLS_ROOT / "common" / "prompts" / "dak_bpmn_constraints.md"
bpmn_xml_schema_path = _SKILLS_ROOT / "common" / "prompts" / "bpmn_xml_schema.md"
actor_context_path = _SKILLS_ROOT / "common" / "prompts" / "actor_context.md"
with dak_bpmn_constraints_path.open(encoding="utf-8") as f:
dak_bpmn_constraints = f.read()
with bpmn_xml_schema_path.open(encoding="utf-8") as f:
bpmn_xml_schema = f.read()
with actor_context_path.open(encoding="utf-8") as f:
actor_context = f.read()
prompt = load_prompt(
"bpmn_author",
"create_or_edit_bpmn",
user_request=f"{issue_title}\n\n{issue_body}",
current_bpmn="(none — creating new BPMN)",
dak_bpmn_constraints=dak_bpmn_constraints,
bpmn_xml_schema=bpmn_xml_schema,
actor_context=actor_context,

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +65
"""
Prompt loader for DAK skill actions.

Prompts are stored as Markdown files with ``{variable}`` placeholders.
``load_prompt()`` reads the file and substitutes variables using
``str.format_map``.

Usage:
from common.prompts import load_prompt

prompt = load_prompt("bpmn_author", "create_or_edit_bpmn",
bpmn_xml="<definitions ...>",
user_request="Add a pharmacy lane")
"""

import os
from pathlib import Path
from typing import Any


# Root of the skills directory (parent of common/)
_SKILLS_ROOT = Path(__file__).resolve().parent.parent


def load_prompt(skill_name: str, prompt_name: str, **variables: Any) -> str:
"""Load a ``.md`` prompt template and fill ``{variable}`` placeholders.

The file is resolved as::

.github/skills/<skill_name>/prompts/<prompt_name>.md

Falls back to::

.github/skills/common/prompts/<prompt_name>.md

Args:
skill_name: Skill directory name (e.g. ``"bpmn_author"``).
prompt_name: Prompt file stem (without ``.md``).
**variables: Substitution values for ``{key}`` placeholders.

Returns:
The rendered prompt string.

Raises:
FileNotFoundError: If neither skill-specific nor common prompt exists.
"""
skill_path = _SKILLS_ROOT / skill_name / "prompts" / f"{prompt_name}.md"
common_path = _SKILLS_ROOT / "common" / "prompts" / f"{prompt_name}.md"

for path in (skill_path, common_path):
if path.is_file():
template = path.read_text(encoding="utf-8")
return template.format_map(_SafeDict(variables))

raise FileNotFoundError(
f"Prompt '{prompt_name}.md' not found in "
f"'{skill_path}' or '{common_path}'"
)


class _SafeDict(dict):
"""dict subclass that returns ``{key}`` for missing keys instead of raising KeyError."""

def __missing__(self, key: str) -> str:
return "{" + key + "}"
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having both common/prompts.py (Python module) and common/prompts/ (directory of .md templates) is a naming collision risk. While it works today because common/prompts/ lacks __init__.py, if anyone ever adds one (e.g., to organize prompt utilities), it would shadow the prompts.py module and break all from common.prompts import load_prompt imports. Consider renaming either the module (e.g., prompt_loader.py) or the directory (e.g., prompt_templates/) to avoid this fragile naming situation.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already applied in c87fd25 — renamed common/prompts.pycommon/prompt_loader.py and updated all imports across the codebase. The common/prompts/ directory of .md templates is now safe from naming collisions.

]


import re
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import re is placed at line 101, after the keyword list constants. Per PEP 8 and the pattern used in other files in this PR (e.g., bpmn_xml_validator.py, swimlane_validator.py, fsh_utils.py which all import re at the top), standard library imports should be grouped at the top of the file alongside the other imports (os, sys, Path).

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already applied in c87fd25 — moved import re to the top of the file alongside os, sys, Path per PEP 8.

Comment on lines +15 to +18
# Only run on pull-request comments that start with /validate
if: >
github.event.issue.pull_request != null &&
startsWith(github.event.comment.body, '/validate')
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says "Lets any collaborator post /validate" but the if condition doesn't verify the commenter's permissions. Any GitHub user (including non-collaborators) can post /validate in a PR comment and trigger a ghbuild.yml workflow dispatch, consuming Actions minutes. Consider adding an author_association check such as contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) to restrict the command to trusted users. The existing pr-deploy-slash.yml has the same gap, but since this is a new workflow and the PR description claims to "Fix critical security issue", this should be addressed here.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already applied in c87fd25 — added contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) to the if condition in pr-validate-slash.yml.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

❌ Deployment Failed

Branch: copilot/create-skills-infrastructure-bpmn
Commit: ac83148

🔍 View Build Log


Deployment failed. Please check the build log for details.

Copilot AI and others added 2 commits March 6, 2026 19:46
…ce.py

Co-authored-by: litlfred <662242+litlfred@users.noreply.github.com>
…loader rename, workflow deps, security, keyword and docstring fixes

Co-authored-by: litlfred <662242+litlfred@users.noreply.github.com>
@litlfred
Copy link
Collaborator

litlfred commented Mar 6, 2026

Propose a solution to resolve the conflicts with upstream and merge @copilot

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

❌ Deployment Failed

Branch: copilot/create-skills-infrastructure-bpmn
Commit: c87fd25

🔍 View Build Log


Deployment failed. Please check the build log for details.

Co-authored-by: litlfred <662242+litlfred@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 6, 2026

Propose a solution to resolve the conflicts with upstream and merge @copilot

Resolved in 4dc6239. The only conflict was in input/scripts/run_ig_publisher.py — our branch didn't independently modify that file, so I took the upstream (main) version entirely using git merge -X theirs. The merge brings in all upstream changes since our last merge base (PRs #298, #300, #301, #303 including: translation config moved to sushi-config.yaml, scripts.pot timestamp-only write skipping, FHIR instance translation extraction fixes, and base.pot source context augmentation).

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

❌ Deployment Failed

Branch: copilot/create-skills-infrastructure-bpmn
Commit: 057c33a

🔍 View Build Log


Deployment failed. Please check the build log for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants